﻿using CKS.PLC.Core;
using CKS.PLC.Core.Event;
using CKS.PLC.Core.Siemens;
using FreeSql;
using Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using NLog;
using S7.Net;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using ZR.Infrastructure;
using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core
{
    /// <summary>
    /// 订阅动作基类
    /// 可根据不同项目自行定义ActionId
    /// </summary>
    public abstract class BasePlcAction
    {
        /// <summary>
        /// 执行批次号Key
        /// </summary>
        public const string _execBatchCodeKey = "ExecBatchCode";

        /// <summary>
        /// 主产品码ActionKey
        /// </summary>
        public const string _primaryCodeActionKey = "PrimaryCode";

        /// <summary>
        /// 保存信号ActionKey
        /// </summary>
        public const string _saveResultRequestActionKey = "SaveResultRequest";


        /// <summary>
        /// Logger
        /// </summary>
        protected static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        public BasePlcAction(DecodeValue _value)
        {
            this.DecodeValue = _value;
            this.SiemensClient = DecodeValue.SiemensClient;
            this.FreeSql = App.ServiceProvider.GetService<IFreeSql<MesDB>>();
        }

        #region Props
        /// <summary>
        /// 解析数据
        /// </summary>
        protected DecodeValue DecodeValue { get; set; }

        /// <summary>
        /// SiemensClient
        /// </summary>
        protected ISiemensClient SiemensClient { get; set; }

        /// <summary>
        /// FreeSql
        /// </summary>
        protected IFreeSql FreeSql { get; private set; }

        #endregion

        #region Methods

        /// <summary>
        /// 获取条码
        /// </summary>
        /// <returns></returns>
        protected string GetMainCodeValue() {

            var position = DecodeValue.Position;

            //获取条码字段位置
            var mainCodePosition = DecodeValue.GetPositionByActionKey(position, _primaryCodeActionKey);

            if (mainCodePosition == null) {
                WriteLogUI($"主条码，未配置ActionKey条码字段，请检查点位配置！");
                return string.Empty;
            }

            var bytes = ReadData(mainCodePosition).GetAwaiter().GetResult();
            string mainCodeValue = Encoding.ASCII.GetString(bytes).Replace("\r", "").Replace($"\0", "").TrimEnd();

            //获取条码值，有问题，获取会存在不是最新的问题
            //mainCodeValue = DecodeValue.GetLinkDecodeObject(mainCodePosition).CharString.TrimEnd();

            return mainCodeValue;
        }

        /// <summary>
        /// 获取字符串后缀
        /// </summary>
        /// <param name="content"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        protected string GetSuffix(string content, int len = 4) {
            if (content.IsNullOrEmpty())
                return "";
            if (content.Length < len)
                return "";
            return content.Substring(content.Length - len);
        }

        /// <summary>
        /// 获取虚拟表下一个序列号
        /// </summary>
        /// <param name="table"></param>
        /// <param name="conn"></param>
        /// <returns></returns>
        protected long GetNextSeq(CksVirtualTable table, DbConnection conn) {
            var n = conn.Select<CksVirtualTable>().Where(a => a.TableName == table.TableName).First();
            return n.MaxSeqId + 1;
        }

        /// <summary>
        /// 执行订阅事件前的操作
        /// </summary>
        public virtual bool ExecuteBefor(Dictionary<string,object> execParams = null) { return true; }

        /// <summary>
        /// 执行订阅事件
        /// </summary>
        public abstract void Execute(Dictionary<string, object> execParams = null);

        /// <summary>
        /// 执行订阅事件后的操作
        /// </summary>
        public virtual void ExecuteAfter(Dictionary<string, object> execParams = null) { }
        

        /// <summary>
        /// 向指定点位写入 int16--对应plc的int值
        /// </summary>
        /// <param name="point"></param>
        /// <param name="value"></param>
        public bool WriteInt16(CksPlcDataPosition point,Int16 value)
        {
            for (int i = 1; i <= 10; i++)
            {
                WriteInt16(point.BlockDb, (int)point.BytePosition, Convert.ToInt16(value));
                var write = ReadInt16(point);
                if (write == value)
                {
                    if (i > 1)
                    {
                        WriteLogUI($"第{i}次写入点位{point.WorkStationCode}-{point.BlockDb}-{point.BytePosition}，计划写入:{value},查询结果:{write}，写入ok");
                    }
                    return true;
                }
                else
                    WriteLogUI($"第{i}次写入点位{point.WorkStationCode}-{point.BlockDb}-{point.BytePosition}，计划写入:{value},查询结果:{write}，不一致");
            }
            throw new Exception($"写入点位{point.WorkStationCode}-{point.BlockDb}-{point.BytePosition}失败");
        }

        /// <summary>
        /// 读取Int点位
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public int ReadInt16(CksPlcDataPosition point)
        {
            return SiemensClient.ReadInt16(point.BlockDb, (int)point.BytePosition);
        }

        /// <summary>
        /// 写入Int点位
        /// </summary>
        /// <param name="db"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public void WriteInt16(int db, int startByteAdr, Int16 value)
        {
            SiemensClient.WriteInt16(db, startByteAdr, value);
        }


        public async Task<byte[]> ReadData(CksPlcDataPosition point)
        {
            return await SiemensClient.ReadBytesAsync(point.BlockDb, (int)point.BytePosition, point.ByteLength);
        }

        public async Task<bool> ReadDataBool(CksPlcDataPosition point)
        {
            int bitindex = (int)(point.BytePosition * 10) % 10;
            var boolByte = await SiemensClient.ReadBytesAsync(point.BlockDb, (int)point.BytePosition, 1);
            var boolValue = DataConversion.GetBit(boolByte[0], bitindex);
            return boolValue;
        }

        /// <summary>
        /// 写入日志显示到UI
        /// </summary>
        /// <param name="message"></param>
        /// <param name="barCode"></param>
        /// <param name="stationCode"></param>
        public void WriteLogUI(string message, string barCode = "", string stationCode = "") {

            if (string.IsNullOrEmpty(stationCode)) {
                stationCode = DecodeValue.Position.WorkStationCode;
            }

            if (barCode == "") {
                barCode = GetMainCodeValue();
            }
            string logMessage = "";

            if (barCode != "") {
                logMessage = $"产品：{barCode}，";
            }

            if (stationCode != "") {
                logMessage += $"在{stationCode}，";
            }

            if (message != "") {
                logMessage += $"{message}";
            }

            EventBus.AddLogInfoToQueues(logMessage);
        }
        #endregion
    }
}
